#include "sharedlib_kdxf.h"
#include <QDebug>
#include "qtts.h"
#include "qisr.h"
#include "qivw.h"
#include "msp_cmn.h"
#include "msp_errors.h"
#include "msp_types.h"
#include <QThread>
#include <QFile>
#include <string>

//默认音频头部数据
struct wave_pcm_hdr default_pcmwavhdr =
{
    { 'R', 'I', 'F', 'F' },
    0,
    {'W', 'A', 'V', 'E'},
    {'f', 'm', 't', ' '},
    16,
    1,
    1,
    16000,
    32000,
    2,
    16,
    {'d', 'a', 't', 'a'},
    0
};

int build_grm_cb(int errorCode, const char *info, void *userData)
{
    if( info==NULL ){
        qDebug()<<"cb grm(no info):"<<errorCode;
    }else{
        qDebug()<<"cb grm:"<<errorCode<<info<<"|"<<userData;
        Sharedlib_kdxf* pThis = (Sharedlib_kdxf*)userData;
        pThis->m_strGamName = QString::fromStdString (info);
    }

    return 0;
}

Sharedlib_kdxf::Sharedlib_kdxf(QObject *parent):QObject(parent)
{
    m_strSpeaker = "xiaofeng";
    m_nNumberSay = 0;
    m_nPitch = 51;
    m_nSpecial = 0;
    m_nSpeed = 51;
    m_nSpeedUp = 1;
    m_textCodec = QTextCodec::codecForName("GB18030");
    m_sessionID = NULL;
}

bool Sharedlib_kdxf::login(QString strAppID)
{
    //用户登录
    QString strLogin = QString("appid=%1, work_dir=.").arg(strAppID);
    QByteArray tmp = m_textCodec->fromUnicode(strLogin);
    int ret = MSPLogin(NULL, NULL, tmp.constData());//第一个参数为用户名，第二个参数为密码，第三个参数是登录参数，用户名和密码需要在http://open.voicecloud.cn注册并获取appid
    if ( ret != MSP_SUCCESS )
    {
        qDebug()<<"MSPLogin error! error code:"<<ret;
        return false;
    }
    qDebug()<<"MSPLogin end..."<<ret;
    return true;
}

void Sharedlib_kdxf::logout()
{
    MSPLogout();
}

void Sharedlib_kdxf::setDefaultParams(QString strSpeaker, int nSpeed, int nPitch, int nSpecial)
{
    m_strSpeaker = strSpeaker;
    m_nPitch = nPitch;
    m_nSpeed = nSpeed;
    m_nSpecial = nSpecial;
}

int Sharedlib_kdxf::getTTSfile(QString strText, QString strFilePath,bool bCloud)
{
    return getTTSfile(strText, strFilePath, m_strSpeaker, m_nSpeed, m_nPitch, m_nSpecial, bCloud);
}

int Sharedlib_kdxf::getTTSfile(QString strText, QString strFilePath, QString strSpeaker, int nSpeed, int nPitch, int nSpecial, bool bCloud)
{
    QString strParams;
    strParams = QString("engine_type=%1, voice_name=%2, speed=%3, volume=99, pitch=%4, tts_res_path=fo|res\\tts\\%5.jet;fo|res\\tts\\common.jet,\
                rdn=%6, rcn=0,text_encoding=GB2312,sample_rate=16000, ttp=text, speed_increase=%7,effect=%8")
                .arg(bCloud?"cloud":"local",strSpeaker).arg(nSpeed).arg(nPitch).arg(strSpeaker).arg(m_nNumberSay).arg(m_nSpeedUp).arg(nSpecial);

    struct wave_pcm_hdr pcmwavhdr = default_pcmwavhdr;
    const char* sess_id = NULL;
    int ret = -1;
    unsigned int text_len = 0;
    unsigned int audio_len = 0;
    int synth_status = MSP_TTS_FLAG_STILL_HAVE_DATA;
    FILE* fp = NULL;

    qDebug()<<"begin to synth..."<<strSpeaker<<nSpeed<<nPitch<<nSpecial<<bCloud;

    QByteArray a1,a2,a3;
    a1 = m_textCodec->fromUnicode(strText);
    a2 = m_textCodec->fromUnicode(strFilePath);
    a3 = m_textCodec->fromUnicode(strParams);
    const char* src_text = a1.constData();
    const char* des_path = a2.constData();
    const char* params = a3.constData();

    text_len = (unsigned int)strlen(src_text);
    fp = fopen(des_path,"wb");
    if (NULL == fp)
    {
        qDebug()<<"open file error:"<<des_path;
        return -1;
    }
    //qDebug()<<params;
    sess_id = QTTSSessionBegin(params, &ret);
    if ( ret != MSP_SUCCESS )
    {
        qDebug()<<"QTTSSessionBegin: qtts begin session failed Error code"<<ret;
        fclose(fp);
        return -1;
    }

    ret = QTTSTextPut(sess_id, src_text, text_len, NULL );
    if ( ret != MSP_SUCCESS )
    {
        qDebug()<<"QTTSTextPut: qtts put text failed Error code"<<ret;
        QTTSSessionEnd(sess_id, "TextPutError");
        fclose(fp);
        return -1;
    }
    fwrite(&pcmwavhdr, sizeof(pcmwavhdr) ,1, fp);
    while (1)
    {
        const void *data = QTTSAudioGet(sess_id, &audio_len, &synth_status, &ret);
        if (NULL != data)
        {
            fwrite(data, audio_len, 1, fp);
            pcmwavhdr.data_size += audio_len;//修正pcm数据的大小
        }
        if (synth_status == MSP_TTS_FLAG_DATA_END || ret != 0)
            break;
    }//合成状态synth_status取值可参考开发文档

    //修正pcm文件头数据的大小
    pcmwavhdr.size_8 += pcmwavhdr.data_size + 36;

    //将修正过的数据写回文件头部
    fseek(fp, 4, 0);
    fwrite(&pcmwavhdr.size_8,sizeof(pcmwavhdr.size_8), 1, fp);
    fseek(fp, 40, 0);
    fwrite(&pcmwavhdr.data_size,sizeof(pcmwavhdr.data_size), 1, fp);
    fclose(fp);

    ret = QTTSSessionEnd(sess_id, NULL);
    if ( ret != MSP_SUCCESS )
    {
        qDebug()<<"QTTSSessionEnd: qtts end failed Error code "<<ret;
    }
    return pcmwavhdr.size_8 + 8;
}

int Sharedlib_kdxf::isr_start(bool bIsOffline, bool bIsChinese)
{
    if( m_sessionID ){
        isr_stop();
    }
    m_bIsOffline = bIsOffline;
    m_bIsChinese = bIsChinese;
    int nError = 0;
    QByteArray bArray;
    if ( bIsOffline )
    {
        pr_strISR_params = QString("ivw_threshold=0:-20,sst=wakeup,aue=speex-wb,ent=sms16k,rst=plain,rse=utf8,engine_type=local,language=%1,\
                                   accent=%2,sample_rate=16000,asr_ptt=false,auf=audio/L16;rate=16000,vad_enable=1,vad_speech_tail=6000,asr_threshold=%3,asr_denoise=%4,\
                asr_res_path=fo|res/asr/common.jet,result_type=xml,text_encoding=utf-8,result_encoding=utf-8,grm_build_path=res/grmTami/%5,local_grammar=%5")
                .arg(bIsChinese?"zh_cn":"en_us").arg("mandarin").arg(0).arg(0).arg(m_strGamName);
        bArray = m_textCodec->fromUnicode(pr_strISR_params);
        m_sessionID = QISRSessionBegin(NULL, bArray.data(), &nError);
    }else{
        pr_strISR_params = QString("ivw_threshold=0:-20,sst=oneshot,aue=speex-wb,ent=sms16k,rst=plain,rse=utf8,engine_type=cloud,language=%1,\
                                   accent=%2,sample_rate=16000,asr_ptt=false,auf=audio/L16;rate=16000,vad_enable=1,vad_speech_tail=6000,asr_threshold=%3,asr_denoise=%4,\
                result_type=plain,text_encoding=utf-8,result_encoding=utf-8")
                .arg(bIsChinese?"zh_cn":"en_us").arg("mandarin").arg(0).arg(0);
        bArray = m_textCodec->fromUnicode(pr_strISR_params);
        m_sessionID = QISRSessionBegin(NULL, bArray.data(), &nError);
    }
   // run

   if ( m_sessionID )
   {
       int epStatus=0, recStatus = 0;
       QISRAudioWrite(m_sessionID, (const void *)NULL, 0, MSP_AUDIO_SAMPLE_FIRST, &epStatus, &recStatus);
       //       qDebug()<<"ASR Begain:"<<epStatus<<recStatus;
   }
   qDebug()<<"Session Begain:"<<m_sessionID<<nError;
   return nError;
}

void Sharedlib_kdxf::isr_stop()
{
    if ( m_sessionID )
    {
        QISRSessionEnd(m_sessionID, NULL);
        m_sessionID = NULL;
    }
}

void Sharedlib_kdxf::isr_parseResult(int recStatus,int epStatus)
{
    int ret = 0;
    const char* rslt;
    if (MSP_REC_STATUS_SUCCESS == recStatus) { //已经有部分听写结果
        rslt = QISRGetResult(m_sessionID, &recStatus, 0, &ret);
        if (MSP_SUCCESS != ret)	{
            qDebug()<<"QISRGetResult failed! error code:"<< ret;
            return;
        }
        if (NULL != rslt){
            emit sig_IsrResult(QString::fromUtf8(rslt));
        }
    }

    if (MSP_EP_AFTER_SPEECH == epStatus){
        isr_stop();
    }

}

void Sharedlib_kdxf::isr_updateAudio(char *pData, int nLen)
{
    if ( m_sessionID )
    {
        int epStatus=0, recStatus = 0;
        int nCount = nLen / MAX_UPDATA_LEN; // 最大上传大小为12800


        for ( int i=0; i < nCount; i++)
        {
            QISRAudioWrite(m_sessionID, pData + i*MAX_UPDATA_LEN, MAX_UPDATA_LEN, MSP_AUDIO_SAMPLE_CONTINUE, &epStatus, &recStatus);
            //qDebug()<<"Upload state:"<<epStatus<<recStatus;
            if(!m_bIsOffline){
                isr_parseResult(recStatus,epStatus);
            }
        }
        int nLastLen = nLen % MAX_UPDATA_LEN;
        if( nLastLen > 0 ){
            QISRAudioWrite(m_sessionID, pData + nLen - nLastLen, nLastLen, MSP_AUDIO_SAMPLE_CONTINUE, &epStatus, &recStatus);
            if(!m_bIsOffline){
                isr_parseResult(recStatus,epStatus);
            }
        }

    }else{
        if(!m_bIsOffline){
            isr_start(m_bIsOffline, m_bIsChinese);
        }
    }
}

void Sharedlib_kdxf::isr_setGramID(QString strIDName)
{
    m_strGamName = strIDName;
}

QString Sharedlib_kdxf::isr_getResult()
{
    QString strRet = "";
    if ( !m_sessionID )
    {
        qDebug()<<"m_sessionID NULL";
        return "";
    }
    int epStatus = 0, recStatus = 0, ret = 0;
    QISRAudioWrite(m_sessionID, (const void *)NULL, 0, MSP_AUDIO_SAMPLE_LAST, &epStatus, &recStatus);

//	qDebug()<<"EndStates:"<<recStatus<<MSP_REC_STATUS_COMPLETE;
    // get result
    int nCount = 0;
    while (recStatus != MSP_REC_STATUS_COMPLETE )
    {
        const char *rslt = QISRGetResult(m_sessionID, &recStatus, 0, &ret);//获取结果
        nCount += 1;
        qDebug()<<"ISR try result:"<<recStatus<<ret;
        if ( rslt )
        {
//            qDebug()<<*rslt;
            strRet = QString::fromUtf8(rslt);
            break;
        }
        if ( recStatus == MSP_REC_STATUS_SUCCESS || ret != 0 || nCount > 35)
        {
            break;
        }

        QThread::msleep(100);
    }
    qDebug()<<"Session End:"<<m_sessionID<<nCount<<recStatus;
    return strRet;
}

bool Sharedlib_kdxf::isr_build_bnf(QString strBnfFileName)
{
    m_strGamName = "";
    QString strFilePath = QString("./msc/bnf/%1.bnf").arg(strBnfFileName);
    QString strParams = QString("engine_type=local,text_encoding = utf-8, asr_res_path=fo|res/asr/common.jet, sample_rate=16000, grm_build_path=res/grmTami/%1").arg(strBnfFileName);

    QByteArray bArry;
    QFile bnfFile(strFilePath);
    if( !bnfFile.open (QIODevice::ReadOnly)){
        qDebug()<<"Open file failed!";
        return false;
    }
    bArry = bnfFile.readAll ();
    bnfFile.close ();
    qDebug()<<strBnfFileName<<bArry.toStdString ().data ();
    // build
    int ret = QISRBuildGrammar("bnf", bArry.data (), bArry.size (), strParams.toUtf8 ().data (), build_grm_cb, this);
    if( ret ){
        return false;
    }
    return true;
}

bool Sharedlib_kdxf::isr_update_bnf(QString key, QString val)
{
    QString strParams = QString("engine_type=local, text_encoding=utf-8, grammar_list=%1, asr_res_path=fo|res/asr/common.jet, sample_rate=16000, grm_build_path=res/asr/GrmBuilld")
            .arg(m_strGamName);
    QByteArray bArry = val.toUtf8 ();
    QByteArray bKeyAscii = m_textCodec->fromUnicode (key);
    // build
    int ret = QISRBuildGrammar(bKeyAscii.data (), bArry.data (), bArry.size (), strParams.toUtf8 ().data (), NULL, NULL);
    if( ret ){
        return false;
    }
    return true;
}



